
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include "semantic.h"
#include "lexical.h"
#include "error.h"
#include "parser.h"
#include "gp_list.h"
#include "symbol.h"
#include "sym_table.h"
#include "common.h"

bool array_semantic_check(var_t *arr, int init_method, const char *str)
{
    if(!arr)
        return false;

    if(init_method == INIT_BY_LIST) {
        int list_len = get_list_len(&arr->arr_init_val);
        if(arr->ele_num == ARR_SIZE_UNKNOWN) {
            arr->ele_num = list_len;
            if(arr->is_ptr) {
                arr->size = 4 * list_len;
            } else {
                arr->size = (arr->type == INT) ? (4 * list_len) : list_len;	
            }
            
        } else if(arr->ele_num < list_len) {
            sem_err(EXCESS_ELEMENTS_IN_ARRAY_INIT, ERROR, arr->name, NULL);
            return false;
        } 
        gp_node_t *node;    
	    list_for_each_entry(node, &arr->arr_init_val, entry) {
            var_t *ele = node->addr;
            if(IS_BASE_CHAR(arr) && !IS_BASE_CHAR(ele)) {
                sem_err(ARRAY_INITIALIZE_BY_WRONG_TYPE, ERROR, arr->name, NULL);
                return false;
            }
		    
            if(IS_BASE_INT(arr) && !IS_BASE(ele)) { // int 兼容 char
                sem_err(ARRAY_INITIALIZE_BY_WRONG_TYPE, ERROR, arr->name, NULL);
                return false;
            }
            // todo 数组元素是整形指针或者字符型指针
            //  例如 char *a[2] = {"hello", "world"};
            if(IS_CHAR_PTR(arr) && !(IS_CHAR_PTR(ele) || is_literal_string(ele))) {
                sem_err(ARRAY_INITIALIZE_BY_WRONG_TYPE, ERROR, arr->name, NULL);
                return false;               
            }

            if(IS_INT_PTR(arr) && !IS_INT_PTR(ele)) {
                sem_err(ARRAY_INITIALIZE_BY_WRONG_TYPE, ERROR, arr->name, NULL);
                return false;               
            }
	    }
        return true;
    } else if(init_method == INIT_BY_STRING) {
        if(!str) 
            return false; // 不会到这里

        if((arr->type != CHAR) || arr->is_ptr) {
            sem_err(INT_ARRAY_INITIALIZE_BY_STRING, ERROR, arr->name, NULL);
            return false;
        }

        if(arr->ele_num == ARR_SIZE_UNKNOWN) {
            arr->ele_num = strlen(str) + 1;
            arr->size = arr->ele_num;
        }

        if(strlen(str) + 1 > arr->ele_num) {
            sem_err(INITIALIZER_STRING_TOO_LONG, ERROR, arr->name, NULL);
            return false;
        }          
        
        var_t *var = new_literal(str, STRING);
        add_str(var);
        arr->init_val = var; 
        return true;            
    }
    return false; // 不会到这里
}

bool var_type_exact_match(var_t *var1, var_t *var2)
{
    assert(var1 && var2);
    return (var1->type == var2->type && 
            var1->is_ptr == var2->is_ptr &&
            var1->is_arr == var2->is_arr &&
            var1->ele_num == var2->ele_num);
   
}



// 用于声明和声明、声明和定义之间的检查。二者函数名一样
bool fun_semantic_check_ok(fun_t *fun1, fun_t *fun2)
{
	assert(fun1 && fun2);
	if((fun1->type != fun2->type) || (fun1->para_len != fun2->para_len) 
                || fun1->is_ptr != fun2->is_ptr)
		return false; // 返回类型不一样或者参数个数不一样

	if(!fun1->para_len) // 都没有参数
		return true;

	gp_node_t *node1, *node2;
	struct list_head *n1 = fun1->para_list_head->next;
	struct list_head *n2 = fun2->para_list_head->next;
	
	int conflict = 0;
	for(int i = 0; i < fun1->para_len; ++i) {
		node1 = container_of(n1, gp_node_t, entry);
		node2 = container_of(n2, gp_node_t, entry);	
        var_t *fun1_param = (var_t *)node1->addr;
        var_t *fun2_param = (var_t *)node2->addr;

        if(!var_type_exact_match(fun1_param, fun2_param)) {  // 类型不一致			
			conflict = 1;  // TODO
			break;
		} 
		n1 = n1->next;
		n2 = n2->next;
	}

	return !conflict;
}
